// utils/validator.js
// 轻量校验器：支持 schema 对 body/query/params 校验、类型转换、默认值、enum、regex、custom 函数

/**
 * schema 例子：
 * {
 *   body: {
 *     phoneNumber: { type: 'string', required: true },
 *     password: { type: 'string', required: true, min: 6 },
 *     type: { type: 'number', required: true, enum: [0,1] },
 *     countryCode: { type: 'string', default: 'CN' },
 *     customField: { custom: (val, ctx) => { if (!myCheck(val)) return '错误信息' } }
 *   },
 *   query: {
 *     pageSize: { type: 'number', default: 10, min: 1 }
 *   },
 *   params: { id: { type: 'number', required: true } }
 * }
 */

function _isEmpty(val) {
    return val === undefined || val === null || val === '';
}

function _castType(val, type) {
    if (val === undefined || val === null) return val;
    if (type === 'string') return String(val);
    if (type === 'number') {
        if (typeof val === 'number') return val;
        const n = Number(val);
        return Number.isNaN(n) ? val : n;
    }
    if (type === 'boolean') {
        if (typeof val === 'boolean') return val;
        if (val === 'true' || val === '1' || val === 1) return true;
        if (val === 'false' || val === '0' || val === 0) return false;
        return val;
    }
    return val;
}

function _checkType(val, type) {
    if (val === undefined || val === null) return true; // other rules handle required
    if (type === 'string') return typeof val === 'string';
    if (type === 'number') return typeof val === 'number' && !Number.isNaN(val);
    if (type === 'boolean') return typeof val === 'boolean';
    if (type === 'array') return Array.isArray(val);
    if (type === 'object') return typeof val === 'object' && !Array.isArray(val);
    return true;
}

function _getLength(val) {
    if (val === undefined || val === null) return 0;
    if (typeof val === 'string' || Array.isArray(val)) return val.length;
    return 0;
}

/**
 * validateSection(schemaSection, dataSection, ctx)
 * 返回 { value: {}, errors: [] }
 */
function validateSection(schemaSection = {}, dataSection = {}, ctx = {}) {
    const out = {};
    const errors = [];

    for (const key of Object.keys(schemaSection)) {
        const rule = schemaSection[key];
        let val = dataSection[key];

        // 默认值
        if (_isEmpty(val) && rule.hasOwnProperty('default')) {
            val = typeof rule.default === 'function' ? rule.default() : rule.default;
        }

        // required
        if (rule.required && _isEmpty(val)) {
            errors.push(`${key} 为必填项`);
            continue;
        }

        // 类型转换（如果有 type 指定）
        if (!_isEmpty(val) && rule.type) {
            val = _castType(val, rule.type);
        }

        // 类型检查
        if (!_isEmpty(val) && rule.type && !_checkType(val, rule.type)) {
            errors.push(`${key} 类型错误，期望 ${rule.type}`);
            continue;
        }

        // string length / number min max
        if (!_isEmpty(val) && rule.type === 'string') {
            if (rule.min && _getLength(val) < rule.min) {
                errors.push(`${key} 最小长度为 ${rule.min}`);
                continue;
            }
            if (rule.max && _getLength(val) > rule.max) {
                errors.push(`${key} 最大长度为 ${rule.max}`);
                continue;
            }
        }
        if (!_isEmpty(val) && rule.type === 'number') {
            if (typeof rule.min === 'number' && val < rule.min) {
                errors.push(`${key} 最小值为 ${rule.min}`);
                continue;
            }
            if (typeof rule.max === 'number' && val > rule.max) {
                errors.push(`${key} 最大值为 ${rule.max}`);
                continue;
            }
        }

        // enum
        if (!_isEmpty(val) && Array.isArray(rule.enum) && !rule.enum.includes(val)) {
            errors.push(`${key} 值无效，允许值：${rule.enum.join(',')}`);
            continue;
        }

        // regex
        if (!_isEmpty(val) && rule.pattern) {
            const re = rule.pattern instanceof RegExp ? rule.pattern : new RegExp(rule.pattern);
            if (!re.test(val)) {
                errors.push(rule.patternMessage || `${key} 格式不正确`);
                continue;
            }
        }

        // custom: 函数返回 true 或返回字符串（错误信息）
        if (!_isEmpty(val) && typeof rule.custom === 'function') {
            try {
                const ret = rule.custom(val, ctx);
                if (ret === false) {
                    errors.push(rule.customMessage || `${key} 自定义校验失败`);
                    continue;
                }
                if (typeof ret === 'string') {
                    errors.push(ret);
                    continue;
                }
            } catch (e) {
                errors.push(rule.customMessage || `${key} 自定义校验异常: ${e.message || e}`);
                continue;
            }
        }

        // 通过：写入输出（保留转换后的值）
        out[key] = val;
    }

    return { value: out, errors };
}

/**
 * validate(schema, data)
 * data = { body, query, params }
 * 返回 { value: {body,query,params}, errors: [] }
 */
function validate(schema = {}, data = {}) {
    const finalValue = {};
    let finalErrors = [];

    const ctx = { body: data.body || {}, query: data.query || {}, params: data.params || {} };

    for (const section of ['body', 'query', 'params']) {
        if (!schema[section]) continue;
        const { value, errors } = validateSection(schema[section], data[section] || {}, ctx);
        finalValue[section] = value;
        if (errors.length) finalErrors = finalErrors.concat(errors);
    }

    return { value: finalValue, errors: finalErrors };
}

module.exports = { validate };